package utility.load_save;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;

import model.area_effect.MapAreaOfEffect;
import model.area_effect.Trap;
import model.core.EntityLibrary;
import model.core.ItemsLibrary;
import model.core.MapAoEsLibrary;
import model.core.MapGoldLibrary;
import model.core.TrapsLibrary;
import model.entity.Entity;
import model.item.InventoryItem;
import model.item.MapGold;
import model.map.*;

/**
 * Class loads the map save file.
 * @author Zachary
 */
public class MapLoader {
	private static String fileDirectory = "GameSaves\\";
	
	/**
	 * Change the file directory.
	 * @param directory
	 */
	public static void changeFileDirectory(String directory){
		fileDirectory = directory;
	}
	
	/**
	 * Load the GameMap from the GameMap save file.
	 * @param map
	 */
	public static void LoadMap(GameMap map){
		FileInputStream fis = null;
		Scanner scanner = null;
		try{
			File file = new File(fileDirectory + "GameMap.save");
			 if(file.exists()){
				 fis = new FileInputStream(file);
				 scanner = new Scanner(fis);
				 
				 // skip over the file title
				 scanner.nextLine();
				 
				 while(scanner.hasNext()){
					 if(scanner.nextLine().equals("[Items]")){
						 parseItems(map, scanner);
					 }
					 else if(scanner.nextLine().equals("[Entities]")){
						 parseEntities(map, scanner);
					 }
					 else if(scanner.nextLine().equals("[Gold]")){
						 parseGold(map, scanner);
					 }
					 else if(scanner.nextLine().equals("[Traps]")){
						 parseTraps(map, scanner);
					 }
					 else if(scanner.nextLine().equals("[MapAreaOfEffects]")){
						 parseMapAoEs(map, scanner);
					 }
					 else if(scanner.nextLine().equals("[States]")){
						 parseStates(map, scanner);
					 }
					 else if(scanner.nextLine().equals("[ShroudedEntities]")){
						 parseShroudedEntities(scanner);
					 }
					 else
						 throw new IOException();
				 }
			 }
			 else{
				 throw new IOException();
			 }
		 }
		 catch(IOException e){
			 System.err.print("There was a problem loading the file.");
			 e.printStackTrace();
		 } finally{
			 if(fis != null){
				 try {
					fis.close();
				 } catch (IOException e) {
					e.printStackTrace();
				 }
				 if(scanner != null)
					 scanner.close();
			 }
		 }
	}
	
	/**
	 * Parse in the MapAoEs from file.
	 * @param map
	 * @param scanner
	 */
	private static void parseMapAoEs(GameMap map, Scanner scanner){
		String[] data = scanner.nextLine().split(";");
		int length = data.length;
		Map<MapPoint, List<MapAreaOfEffect>> mapAoEs = new HashMap<MapPoint, 
		 List<MapAreaOfEffect>>();
		
		for(int i = 0;i<length;++i){
			List<MapAreaOfEffect> maoe = new ArrayList<MapAreaOfEffect>();
			String[] individualData = data[i].split(" ");
			MapPoint p = new MapPoint(individualData[0]);
			
			String[] m = individualData[1].split("~");
			for(int j = 0;j<m.length;++j)
				maoe.add(MapAoEsLibrary.getInstance().getMapAreaOfEffect(m[j]));
			
			mapAoEs.put(p, maoe);
		}
		
		map.buildMapAreaOfEffectMap(mapAoEs);
	}
	
	/**
	 * Parse in the traps from file.
	 * @param map
	 * @param scanner
	 */
	private static void parseTraps(GameMap map, Scanner scanner){
		String[] data = scanner.nextLine().split(";");
		int length = data.length;
		Map<MapPoint, List<Trap>> traps = new HashMap<MapPoint, 
		 List<Trap>>();
		
		for(int i = 0;i<length;++i){
			List<Trap> t = new ArrayList<Trap>();
			String[] individualData = data[i].split(" ");
			MapPoint p = new MapPoint(individualData[0]);
			
			String[] m = individualData[1].split("~");
			for(int j = 0;j<m.length;++j)
				t.add(TrapsLibrary.getInstance().getTrap(m[j]));
			
			traps.put(p, t);
		}
		
		map.buildTrapMap(traps);
	}

	/**
	 * Parse in the MapGold from file.
	 * @param map
	 * @param scanner
	 */
	private static void parseGold(GameMap map, Scanner scanner){
		String[] data = scanner.nextLine().split(";");
		int length = data.length;
		Map<MapPoint, List<MapGold>> gold = new HashMap<MapPoint, 
		 List<MapGold>>();
		
		for(int i = 0;i<length;++i){
			List<MapGold> g = new ArrayList<MapGold>();
			String[] individualData = data[i].split(" ");
			MapPoint p = new MapPoint(individualData[0]);
			
			String[] m = individualData[1].split("~");
			for(int j = 0;j<m.length;++j)
				g.add(MapGoldLibrary.getInstance().getMapGold(m[j]));
			
			gold.put(p, g);
		}
		
		map.buildGoldMap(gold);
	}

	/**
	 * Parse in the items from file.
	 * @param map
	 * @param scanner
	 */
	private static void parseItems(GameMap map, Scanner scanner){
		String[] data = scanner.nextLine().split(";");
		int length = data.length;
		Map<MapPoint, List<InventoryItem>> items = new HashMap<MapPoint, 
		 List<InventoryItem>>();
		
		for(int i = 0;i<length;++i){
			List<InventoryItem> it = new ArrayList<InventoryItem>();
			String[] individualData = data[i].split(" ");
			MapPoint p = new MapPoint(individualData[0]);
			
			String[] m = individualData[1].split("~");
			for(int j = 0;j<m.length;++j)
				it.add(ItemsLibrary.getInstance().getItem(m[j]));
			
			items.put(p, it);
		}
		
		map.buildItemMap(items);
	}

	/**
	 * Parse in the entities from file.
	 * @param map
	 * @param scanner
	 */
	private static void parseEntities(GameMap map, Scanner scanner){
		String[] data = scanner.nextLine().split(";");
		int length = data.length;
		Map<MapPoint, List<Entity>> entities = new HashMap<MapPoint, 
		 List<Entity>>();
		
		for(int i = 0;i<length;++i){
			List<Entity> e = new ArrayList<Entity>();
			String[] individualData = data[i].split(" ");
			MapPoint p = new MapPoint(individualData[0]);
			
			String[] m = individualData[1].split("~");
			for(int j = 0;j<m.length;++j)
				e.add(EntityLibrary.getInstance().getEntity(m[j]));
			
			entities.put(p, e);
		}
		
		map.buildEntityMap(entities);
	}

	/**
	 * Parse in the MapTileStates from file.
	 * @param map
	 * @param scanner
	 */
	private static void parseStates(GameMap map, Scanner scanner){
		String[] data = scanner.nextLine().split(";");
		int length = data.length;
		Map<MapPoint, MapTileState> mapStates = new HashMap<MapPoint, 
		 MapTileState>();
		
		for(int i = 0;i<length;++i){
			MapTileState m = null;
			String[] individualData = data[i].split(" ");
			MapPoint p = new MapPoint(individualData[0]);
			
			String name = individualData[1];
			if(name.equals("Shrouded"))
				m = new Shrouded(map,p);
			else
				m = new CurrentlyViewable(map,p);
			
			String[] states = individualData[1].split("~");
			Queue<String> renders = new LinkedList<String>();
			for(int j = 0;j<states.length;++j)
				renders.add(states[j]);
			m.setPulledData(renders);
			
			mapStates.put(p, m);
		}
		
		map.buildStateMap(mapStates);
	}

	/**
	 * Add the shrouded entities to the map visitor shrouded entity list.
	 * @param scanner
	 */
	private static void parseShroudedEntities(Scanner scanner){
		String[] data = scanner.nextLine().split(";");
		int length = data.length;
		
		for(int i = 0;i<length;++i){
			String[] individualData = data[i].split(" ");
			MapPoint p = new MapPoint(individualData[0]);
			
			Entity e = EntityLibrary.getInstance().getEntity(individualData[1]);
			MapVisitor.addToShrouded(e, p);
		}
	}
}
